<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Kafka监控中心</title>
    <!-- 引入外部资源 -->
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
    <script src="/api/chart.umd.min.js"></script>

    <!-- Tailwind配置 -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#165DFF',
                        success: '#00B42A',
                        warning: '#FF7D00',
                        danger: '#F53F3F',
                        info: '#86909C',
                        dark: '#1D2129',
                        light: '#F2F3F5'
                    },
                    fontFamily: {
                        inter: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>

    <style type="text/tailwindcss">
        @layer utilities {
            .card-shadow {
                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
            }
            .card-hover {
                transition: all 0.3s ease;
            }
            .card-hover:hover {
                transform: translateY(-3px);
                box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
            }
            .scrollbar-hide::-webkit-scrollbar {
                display: none;
            }
            .scrollbar-hide {
                -ms-overflow-style: none;
                scrollbar-width: none;
            }
            .modal-backdrop {
                backdrop-filter: blur(4px);
            }
            .form-input-focus {
                @apply focus:outline-none focus:ring-2 focus:ring-primary/50 border-primary;
            }
        }
    </style>
</head>
<body class="font-inter bg-gray-50 text-dark min-h-screen">
<!-- 顶部导航栏 -->
<header class="bg-white card-shadow sticky top-0 z-50">
    <div class="container mx-auto px-4 py-3 flex items-center justify-between">
        <div class="flex items-center space-x-2">
            <i class="fa fa-line-chart text-primary text-2xl"></i>
            <h1 class="text-xl md:text-2xl font-bold text-primary">Kafka 监控中心</h1>
        </div>

        <div class="flex items-center space-x-4">
            <div class="hidden md:flex items-center space-x-2 bg-light rounded-full px-4 py-2">
                <i class="fa fa-refresh text-primary mr-2"></i>
                <span id="refresh-status">已刷新</span>
            </div>

            <!-- 新增按钮组 -->
            <div class="flex space-x-2">
                <button id="config-btn" class="bg-info hover:bg-info/90 text-white rounded-full px-4 py-2 flex items-center">
                    <i class="fa fa-cog mr-2"></i>
                    <span class="hidden md:inline">配置</span>
                </button>
                <button id="create-topic-btn" class="bg-success hover:bg-success/90 text-white rounded-full px-4 py-2 flex items-center">
                    <i class="fa fa-plus mr-2"></i>
                    <span class="hidden md:inline">新建主题</span>
                </button>
            </div>

            <button id="refresh-btn" class="bg-primary hover:bg-primary/90 text-white rounded-full px-4 py-2 flex items-center">
                <i class="fa fa-refresh mr-2"></i>
                <span>刷新</span>
            </button>
        </div>
    </div>
</header>

<!-- 主内容区 -->
<main class="container mx-auto px-4 py-6">
    <!-- 集群状态概览 -->
    <section class="mb-8">
        <div class="flex items-center justify-between mb-4">
            <h2 class="text-xl font-bold flex items-center">
                <i class="fa fa-server text-primary mr-2"></i>
                集群状态概览
            </h2>
            <div class="flex items-center space-x-2">
                <span id="cluster-name" class="text-sm text-info">未连接</span>
                <span id="cluster-status" class="bg-warning text-white text-sm px-3 py-1 rounded-full">
                        <i class="fa fa-exclamation-circle mr-1"></i>未连接
                    </span>
            </div>
        </div>

        <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
            <!-- 节点数量 -->
            <div class="bg-white rounded-xl p-4 card-shadow card-hover">
                <div class="flex justify-between items-start">
                    <div>
                        <p class="text-info text-sm mb-1">Broker节点数</p>
                        <h3 id="broker-count" class="text-2xl font-bold">-</h3>
                    </div>
                    <div class="bg-primary/10 p-3 rounded-full">
                        <i class="fa fa-server text-primary text-xl"></i>
                    </div>
                </div>
                <div class="mt-3 flex items-center text-sm">
                        <span id="broker-change" class="text-info flex items-center">
                            <i class="fa fa-minus mr-1"></i> --
                        </span>
                    <span class="text-info ml-2">24小时内</span>
                </div>
            </div>

            <!-- 主题数量 -->
            <div class="bg-white rounded-xl p-4 card-shadow card-hover">
                <div class="flex justify-between items-start">
                    <div>
                        <p class="text-info text-sm mb-1">主题数量</p>
                        <h3 id="topic-count" class="text-2xl font-bold">-</h3>
                    </div>
                    <div class="bg-primary/10 p-3 rounded-full">
                        <i class="fa fa-list-alt text-primary text-xl"></i>
                    </div>
                </div>
                <div class="mt-3 flex items-center text-sm">
                        <span id="topic-change" class="text-info flex items-center">
                            <i class="fa fa-minus mr-1"></i> --
                        </span>
                    <span class="text-info ml-2">24小时内</span>
                </div>
            </div>

            <!-- 分区总数 -->
            <div class="bg-white rounded-xl p-4 card-shadow card-hover">
                <div class="flex justify-between items-start">
                    <div>
                        <p class="text-info text-sm mb-1">分区总数</p>
                        <h3 id="partition-count" class="text-2xl font-bold">-</h3>
                    </div>
                    <div class="bg-primary/10 p-3 rounded-full">
                        <i class="fa fa-th text-primary text-xl"></i>
                    </div>
                </div>
                <div class="mt-3 flex items-center text-sm">
                        <span id="partition-change" class="text-info flex items-center">
                            <i class="fa fa-minus mr-1"></i> --
                        </span>
                    <span class="text-info ml-2">24小时内</span>
                </div>
            </div>

            <!-- 消息总量 -->
            <div class="bg-white rounded-xl p-4 card-shadow card-hover">
                <div class="flex justify-between items-start">
                    <div>
                        <p class="text-info text-sm mb-1">消息总量(24h)</p>
                        <h3 id="message-total" class="text-2xl font-bold">-</h3>
                    </div>
                    <div class="bg-primary/10 p-3 rounded-full">
                        <i class="fa fa-envelope text-primary text-xl"></i>
                    </div>
                </div>
                <div class="mt-3 flex items-center text-sm">
                        <span id="message-change" class="text-info flex items-center">
                            <i class="fa fa-minus mr-1"></i> --
                        </span>
                    <span class="text-info ml-2">较昨日</span>
                </div>
            </div>
        </div>
    </section>

    <!-- 流量监控图表 -->
    <section class="mb-8">
        <div class="bg-white rounded-xl p-4 card-shadow">
            <div class="flex flex-col md:flex-row md:items-center justify-between mb-4">
                <h2 class="text-xl font-bold flex items-center mb-2 md:mb-0">
                    <i class="fa fa-area-chart text-primary mr-2"></i>
                    流量监控 (消息/秒)
                </h2>
                <div class="flex space-x-2">
                    <button class="chart-filter-btn bg-primary text-white px-3 py-1 rounded-md text-sm">实时</button>
                    <button class="chart-filter-btn bg-light text-info px-3 py-1 rounded-md text-sm">1小时</button>
                    <button class="chart-filter-btn bg-light text-info px-3 py-1 rounded-md text-sm">24小时</button>
                    <button class="chart-filter-btn bg-light text-info px-3 py-1 rounded-md text-sm">7天</button>
                </div>
            </div>
            <div class="h-64">
                <canvas id="throughput-chart"></canvas>
            </div>
        </div>
    </section>

    <!-- 主题详情表格 -->
    <section class="mb-8">
        <div class="flex items-center justify-between mb-4">
            <h2 class="text-xl font-bold flex items-center">
                <i class="fa fa-list-alt text-primary mr-2"></i>
                主题详情
            </h2>
            <div class="relative">
                <input type="text" id="topic-search" placeholder="搜索主题..."
                       class="pl-10 pr-4 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/50">
                <i class="fa fa-search absolute left-3 top-1/2 transform -translate-y-1/2 text-info"></i>
            </div>
        </div>

        <div class="bg-white rounded-xl card-shadow overflow-hidden">
            <div class="overflow-x-auto">
                <table class="w-full">
                    <thead>
                    <tr class="bg-light">
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">主题名称</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">分区数</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">副本数</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">生产速率</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">消费速率</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">积压量</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">状态</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">操作</th>
                    </tr>
                    </thead>
                    <tbody id="topic-table-body">
                    <tr>
                        <td colspan="8" class="px-6 py-4 text-center text-info">
                            <i class="fa fa-spinner fa-spin mr-2"></i>加载中...
                        </td>
                    </tr>
                    </tbody>
                </table>
            </div>
            <div class="px-6 py-4 border-t border-gray-100 flex justify-between items-center">
                <div class="text-sm text-info">共 <span id="topic-total">0</span> 个主题</div>
                <div class="flex space-x-2">
                    <button id="prev-topic-page" class="px-3 py-1 border border-gray-200 rounded-md text-sm disabled:opacity-50" disabled>上一页</button>
                    <button class="px-3 py-1 bg-primary text-white rounded-md text-sm">1</button>
                    <button id="next-topic-page" class="px-3 py-1 border border-gray-200 rounded-md text-sm">下一页</button>
                </div>
            </div>
        </div>
    </section>

    <!-- 消费者组监控 -->
    <section>
        <div class="flex items-center justify-between mb-4">
            <h2 class="text-xl font-bold flex items-center">
                <i class="fa fa-users text-primary mr-2"></i>
                消费者组监控
            </h2>
            <div class="relative">
                <input type="text" id="consumer-group-search" placeholder="搜索消费者组..."
                       class="pl-10 pr-4 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/50">
                <i class="fa fa-search absolute left-3 top-1/2 transform -translate-y-1/2 text-info"></i>
            </div>
        </div>

        <div class="bg-white rounded-xl card-shadow overflow-hidden">
            <div class="overflow-x-auto">
                <table class="w-full">
                    <thead>
                    <tr class="bg-light">
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">消费者组ID</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">订阅主题</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">消费者数量</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">消费速率</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">总积压量</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">当前位移</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">末端位移</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">最大延迟(ms)</th>
                        <th class="px-6 py-3 text-left text-sm font-semibold text-dark">状态</th>
                    </tr>
                    </thead>
                    <tbody id="consumer-group-table-body">
                    <tr>
                        <td colspan="9" class="px-6 py-4 text-center text-info">
                            <i class="fa fa-spinner fa-spin mr-2"></i>加载中...
                        </td>
                    </tr>
                    </tbody>
                </table>
            </div>
            <div class="px-6 py-4 border-t border-gray-100 flex justify-between items-center">
                <div class="text-sm text-info">共 <span id="consumer-group-total">0</span> 个消费者组</div>
                <div class="flex space-x-2">
                    <button id="prev-consumer-page" class="px-3 py-1 border border-gray-200 rounded-md text-sm disabled:opacity-50" disabled>上一页</button>
                    <button class="px-3 py-1 bg-primary text-white rounded-md text-sm">1</button>
                    <button id="next-consumer-page" class="px-3 py-1 border border-gray-200 rounded-md text-sm">下一页</button>
                </div>
            </div>
        </div>
    </section>
</main>

<!-- 页脚 -->
<footer class="bg-white border-t border-gray-200 py-4 mt-8">
    <div class="container mx-auto px-4 text-center text-info text-sm">
        <p>Kafka监控中心 v1.0.0 | 数据更新时间: <span id="update-time">-</span></p>
    </div>
</footer>

<!-- 配置Kafka连接信息模态框 -->
<div id="config-modal" class="fixed inset-0 z-50 flex items-center justify-center hidden">
    <div class="absolute inset-0 bg-black bg-opacity-50 modal-backdrop"></div>
    <div class="bg-white rounded-xl p-6 w-full max-w-md relative z-10 transform transition-all duration-300 scale-95 opacity-0" id="config-modal-content">
        <div class="flex justify-between items-center mb-4">
            <h3 class="text-xl font-bold text-primary">Kafka连接配置</h3>
            <button id="close-config-modal" class="text-info hover:text-dark">
                <i class="fa fa-times text-xl"></i>
            </button>
        </div>

        <form id="kafka-config-form">
            <div class="mb-4">
                <label for="bootstrap-servers" class="block text-sm font-medium text-dark mb-1">Bootstrap Servers</label>
                <input type="text" id="bootstrap-servers" name="bootstrapServers"
                       class="w-full px-3 py-2 border border-gray-200 rounded-lg form-input-focus"
                       placeholder="localhost:9092,localhost:9093" required>
            </div>

            <div class="mb-4">
                <label for="admin-timeout" class="block text-sm font-medium text-dark mb-1">Admin Timeout (ms)</label>
                <input type="number" id="admin-timeout" name="adminTimeout"
                       class="w-full px-3 py-2 border border-gray-200 rounded-lg form-input-focus"
                       value="5000" min="1000" max="30000" required>
            </div>

            <div class="mb-4">
                <label for="metrics-refresh-interval" class="block text-sm font-medium text-dark mb-1">指标刷新间隔 (ms)</label>
                <input type="number" id="metrics-refresh-interval" name="metricsRefreshInterval"
                       class="w-full px-3 py-2 border border-gray-200 rounded-lg form-input-focus"
                       value="30000" min="5000" max="300000" required>
            </div>

            <div class="mb-6">
                <label for="consumer-group-id" class="block text-sm font-medium text-dark mb-1">消费者组ID</label>
                <input type="text" id="consumer-group-id" name="consumerGroupId"
                       class="w-full px-3 py-2 border border-gray-200 rounded-lg form-input-focus"
                       value="kafka-monitor-group" required>
            </div>

            <div class="flex justify-end space-x-3">
                <button type="button" id="reset-config-btn" class="px-4 py-2 border border-gray-200 rounded-lg text-dark hover:bg-light">
                    重置
                </button>
                <button type="submit" class="px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90">
                    保存配置
                </button>
            </div>
        </form>
    </div>
</div>

<!-- 新增Topic模态框 -->
<div id="create-topic-modal" class="fixed inset-0 z-50 flex items-center justify-center hidden">
    <div class="absolute inset-0 bg-black bg-opacity-50 modal-backdrop"></div>
    <div class="bg-white rounded-xl p-6 w-full max-w-md relative z-10 transform transition-all duration-300 scale-95 opacity-0" id="create-topic-modal-content">
        <div class="flex justify-between items-center mb-4">
            <h3 class="text-xl font-bold text-primary">创建Kafka主题</h3>
            <button id="close-topic-modal" class="text-info hover:text-dark">
                <i class="fa fa-times text-xl"></i>
            </button>
        </div>

        <form id="create-topic-form">
            <div class="mb-4">
                <label for="topic-name" class="block text-sm font-medium text-dark mb-1">主题名称</label>
                <input type="text" id="topic-name" name="topicName"
                       class="w-full px-3 py-2 border border-gray-200 rounded-lg form-input-focus"
                       placeholder="my-topic" required>
            </div>

            <div class="mb-4">
                <label for="partition-count" class="block text-sm font-medium text-dark mb-1">分区数</label>
                <input type="number" id="partition-count-input" name="partitionCount"
                       class="w-full px-3 py-2 border border-gray-200 rounded-lg form-input-focus"
                       value="3" min="1" max="100" required>
            </div>

            <div class="mb-4">
                <label for="replica-count" class="block text-sm font-medium text-dark mb-1">副本数</label>
                <input type="number" id="replica-count" name="replicaCount"
                       class="w-full px-3 py-2 border border-gray-200 rounded-lg form-input-focus"
                       value="2" min="1" max="10" required>
            </div>

            <div class="mb-6">
                <label for="retention-ms" class="block text-sm font-medium text-dark mb-1">消息保留时间 (s)</label>
                <input type="number" id="retention-ms" name="retentionMs"
                       class="w-full px-3 py-2 border border-gray-200 rounded-lg form-input-focus"
                       value="604800" min="86400" max="31536000" required>
                <p class="text-xs text-info mt-1">默认: 604800 s (7天)</p>
            </div>

            <div class="flex justify-end space-x-3">
                <button type="button" id="cancel-create-topic" class="px-4 py-2 border border-gray-200 rounded-lg text-dark hover:bg-light">
                    取消
                </button>
                <button type="submit" class="px-4 py-2 bg-success text-white rounded-lg hover:bg-success/90">
                    创建主题
                </button>
            </div>
        </form>
    </div>
</div>

<!-- 确认删除模态框 -->
<div id="confirm-delete-modal" class="fixed inset-0 z-50 flex items-center justify-center hidden">
    <div class="absolute inset-0 bg-black bg-opacity-50 modal-backdrop"></div>
    <div class="bg-white rounded-xl p-6 w-full max-w-md relative z-10 transform transition-all duration-300 scale-95 opacity-0" id="confirm-delete-modal-content">
        <div class="flex justify-between items-center mb-4">
            <h3 class="text-xl font-bold text-danger">确认删除</h3>
            <button id="close-confirm-modal" class="text-info hover:text-dark">
                <i class="fa fa-times text-xl"></i>
            </button>
        </div>

        <p class="mb-6">您确定要删除主题 <span id="delete-topic-name" class="font-medium text-dark">topic-name</span> 吗？此操作不可撤销。</p>

        <div class="flex justify-end space-x-3">
            <button id="cancel-delete" class="px-4 py-2 border border-gray-200 rounded-lg text-dark hover:bg-light">
                取消
            </button>
            <button id="confirm-delete" class="px-4 py-2 bg-danger text-white rounded-lg hover:bg-danger/90">
                确认删除
            </button>
        </div>
    </div>
</div>

<!-- 通知提示 -->
<div id="toast-container" class="fixed bottom-4 right-4 z-50 max-w-sm"></div>

<!-- JavaScript -->
<script>
    // 全局变量
    let throughputChart = null;
    let topicData = [];
    let consumerGroupData = [];
    let currentTopicPage = 1;
    let currentConsumerPage = 1;
    let topicsPerPage = 8;
    let consumersPerPage = 8;
    let deletingTopicName = '';

    // API配置
    let apiConfig = {
        baseUrl: 'http://localhost:8888/api',
        kafkaConfig: {
            bootstrapServers: 'localhost:9092',
            adminTimeout: 5000,
            metricsRefreshInterval: 30000,
            consumerGroupId: 'kafka-monitor-group'
        }
    };

    // 从localStorage加载配置
    const loadConfigFromStorage = () => {
        const savedConfig = localStorage.getItem('kafkaMonitorConfig');
        if (savedConfig) {
            try {
                const parsedConfig = JSON.parse(savedConfig);
                apiConfig = parsedConfig;
                updateConfigForm();
            } catch (e) {
                console.error('Failed to parse saved config:', e);
            }
        }
    };

    // 保存配置到localStorage
    const saveConfigToStorage = () => {
        localStorage.setItem('kafkaMonitorConfig', JSON.stringify(apiConfig));
    };

    // 更新配置表单
    const updateConfigForm = () => {
        document.getElementById('bootstrap-servers').value = apiConfig.kafkaConfig.bootstrapServers;
        document.getElementById('admin-timeout').value = apiConfig.kafkaConfig.adminTimeout;
        document.getElementById('metrics-refresh-interval').value = apiConfig.kafkaConfig.metricsRefreshInterval;
        document.getElementById('consumer-group-id').value = apiConfig.kafkaConfig.consumerGroupId;
    };

    // 初始化图表
    const initThroughputChart = (labels = [], producerData = [], consumerData = []) => {
        const ctx = document.getElementById('throughput-chart').getContext('2d');

        // 如果图表已存在，销毁它
        if (throughputChart) {
            throughputChart.destroy();
        }

        // 使用默认数据如果没有提供
        if (labels.length === 0) {
            labels = Array.from({length: 20}, (_, i) => `${i * 3}s`);
            producerData = labels.map(() => Math.floor(Math.random() * 5000) + 1000);
            consumerData = labels.map((_, i) => producerData[i] - Math.floor(Math.random() * 1000));
        }

        throughputChart = new Chart(ctx, {
            type: 'line',
            data: {
                labels: labels,
                datasets: [
                    {
                        label: '生产速率',
                        data: producerData,
                        borderColor: '#165DFF',
                        backgroundColor: 'rgba(22, 93, 255, 0.1)',
                        tension: 0.4,
                        fill: true
                    },
                    {
                        label: '消费速率',
                        data: consumerData,
                        borderColor: '#00B42A',
                        backgroundColor: 'rgba(0, 180, 42, 0.1)',
                        tension: 0.4,
                        fill: true
                    }
                ]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: {
                        position: 'top',
                    },
                    tooltip: {
                        mode: 'index',
                        intersect: false,
                    }
                },
                scales: {
                    y: {
                        beginAtZero: true,
                        grid: {
                            drawBorder: false,
                            color: 'rgba(0, 0, 0, 0.05)'
                        }
                    },
                    x: {
                        grid: {
                            display: false
                        }
                    }
                },
                interaction: {
                    mode: 'nearest',
                    axis: 'x',
                    intersect: false
                },
                animation: {
                    duration: 1000
                }
            }
        });
    };

    // 格式化数字
    const formatNumber = (num) => {
        if (num >= 1000000) {
            return (num / 1000000).toFixed(1) + 'M';
        } else if (num >= 1000) {
            return (num / 1000).toFixed(1) + 'K';
        }
        return num.toString();
    };

    // 格式化速率
    const formatRate = (rate) => {
        if (rate >= 1000) {
            return (rate / 1000).toFixed(1) + 'k/s';
        }
        return Math.round(rate) + '/s';
    };



    // 获取流量监控数据
    const fetchThroughputMetrics = async (topicName = null, timeRange = '24hour') => {
        try {
            const params = new URLSearchParams();
            if (topicName) params.append('topicName', topicName);
            params.append('timeRange', timeRange);

            const response = await fetch(`${apiConfig.baseUrl}/kafka/metrics/throughput?${params}`);

            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }

            const data = await response.json();
            return data;
        } catch (error) {
            console.error('Failed to fetch throughput metrics:', error);
            showToast('获取流量监控数据失败: ' + error.message, 'error');
            return null;
        }
    };

    // 更新图表数据
    const updateThroughputChart = async (timeRange = '24hour') => {
        // 默认查询所有主题的数据
        const metricsData = await fetchThroughputMetrics(null, timeRange);
        if (metricsData && throughputChart) {
            throughputChart.data.labels = metricsData.timestamps;
            throughputChart.data.datasets[0].data = metricsData.produceRates;
            throughputChart.data.datasets[1].data = metricsData.consumeRates;
            throughputChart.update();
        }
    };


    // 修改图表筛选按钮事件处理器
    document.querySelectorAll('.chart-filter-btn').forEach(btn => {
        btn.addEventListener('click', async () => {
            document.querySelectorAll('.chart-filter-btn').forEach(b => {
                b.classList.remove('bg-primary', 'text-white');
                b.classList.add('bg-light', 'text-info');
            });
            btn.classList.remove('bg-light', 'text-info');
            btn.classList.add('bg-primary', 'text-white');

            // 根据选择的时间范围更新图表数据
            let timeRange = '24hour';
            switch(btn.textContent.trim()) {
                case '实时':
                    timeRange = 'realtime';
                    break;
                case '1小时':
                    timeRange = '1hour';
                    break;
                case '24小时':
                    timeRange = '24hour';
                    break;
                case '7天':
                    timeRange = '7day';
                    break;
            }

            await updateThroughputChart(timeRange);
        });
    });



    // 渲染主题表格
    const renderTopicTable = (page = 1, searchTerm = '') => {
        const tableBody = document.getElementById('topic-table-body');
        const topicTotal = document.getElementById('topic-total');

        // 过滤数据
        let filteredTopics = topicData;
        if (searchTerm) {
            filteredTopics = topicData.filter(topic =>
                topic.topicName.toLowerCase().includes(searchTerm.toLowerCase())
            );
        }

        // 更新总数
        topicTotal.textContent = filteredTopics.length;

        // 分页
        const startIndex = (page - 1) * topicsPerPage;
        const endIndex = Math.min(startIndex + topicsPerPage, filteredTopics.length);
        const paginatedTopics = filteredTopics.slice(startIndex, endIndex);

        // 更新分页按钮状态
        document.getElementById('prev-topic-page').disabled = page === 1;
        document.getElementById('next-topic-page').disabled = endIndex >= filteredTopics.length;

        // 清空表格
        tableBody.innerHTML = '';

        // 显示无数据提示
        if (paginatedTopics.length === 0) {
            const row = document.createElement('tr');
            row.innerHTML = `
                    <td colspan="8" class="px-6 py-4 text-center text-info">
                        <i class="fa fa-info-circle mr-2"></i>没有找到匹配的主题
                    </td>
                `;
            tableBody.appendChild(row);
            return;
        }

        // 渲染表格数据
        paginatedTopics.forEach(topic => {
            const row = document.createElement('tr');
            row.className = 'border-b border-gray-100 hover:bg-gray-50 transition-colors';

            // 状态样式
            let statusClass, statusIcon;
            if (topic.status === '健康') {
                statusClass = 'bg-success/10 text-success';
                statusIcon = 'fa-check-circle';
            } else if (topic.status === '警告') {
                statusClass = 'bg-warning/10 text-warning';
                statusIcon = 'fa-exclamation-circle';
            } else {
                statusClass = 'bg-danger/10 text-danger';
                statusIcon = 'fa-times-circle';
            }

            row.innerHTML = `
                    <td class="px-6 py-4">
                        <div class="font-medium">${topic.topicName}</div>
                    </td>
                    <td class="px-6 py-4">${topic.partitionCount}</td>
                    <td class="px-6 py-4">${topic.replicaCount}</td>
                    <td class="px-6 py-4">${formatRate(topic.produceRate)}</td>
                    <td class="px-6 py-4">${formatRate(topic.consumeRate)}</td>
                    <td class="px-6 py-4">${formatNumber(topic.backlog)}</td>
                    <td class="px-6 py-4">
                        <span class="px-2 py-1 rounded-full text-xs ${statusClass}">
                            <i class="fa ${statusIcon} mr-1"></i>${topic.status}
                        </span>
                    </td>
                    <td class="px-6 py-4">
                        <button class="delete-topic-btn text-danger hover:text-danger/80" data-topic="${topic.topicName}">
                            <i class="fa fa-trash"></i> 删除
                        </button>
                    </td>
                `;

            tableBody.appendChild(row);
        });

        // 添加删除按钮事件
        document.querySelectorAll('.delete-topic-btn').forEach(btn => {
            btn.addEventListener('click', (e) => {
                const topicName = e.currentTarget.getAttribute('data-topic');
                showConfirmDeleteModal(topicName);
            });
        });
    };

    // 渲染消费者组表格
    const renderConsumerGroupTable = (page = 1, searchTerm = '') => {
        const tableBody = document.getElementById('consumer-group-table-body');
        const consumerGroupTotal = document.getElementById('consumer-group-total');

        // 过滤数据
        let filteredGroups = consumerGroupData;
        if (searchTerm) {
            filteredGroups = consumerGroupData.filter(group =>
                group.groupId.toLowerCase().includes(searchTerm.toLowerCase()) ||
                group.topicName.toLowerCase().includes(searchTerm.toLowerCase())
            );
        }

        // 更新总数
        consumerGroupTotal.textContent = filteredGroups.length;

        // 分页
        const startIndex = (page - 1) * consumersPerPage;
        const endIndex = Math.min(startIndex + consumersPerPage, filteredGroups.length);
        const paginatedGroups = filteredGroups.slice(startIndex, endIndex);

        // 更新分页按钮状态
        document.getElementById('prev-consumer-page').disabled = page === 1;
        document.getElementById('next-consumer-page').disabled = endIndex >= filteredGroups.length;

        // 清空表格
        tableBody.innerHTML = '';

        // 显示无数据提示
        if (paginatedGroups.length === 0) {
            const row = document.createElement('tr');
            row.innerHTML = `
                    <td colspan="9" class="px-6 py-4 text-center text-info">
                        <i class="fa fa-info-circle mr-2"></i>没有找到匹配的消费者组
                    </td>
                `;
            tableBody.appendChild(row);
            return;
        }

        // 渲染表格数据
        paginatedGroups.forEach(group => {
            const row = document.createElement('tr');
            row.className = 'border-b border-gray-100 hover:bg-gray-50 transition-colors';

            // 状态样式
            let statusClass, statusIcon;
            if (group.state === '健康') {
                statusClass = 'bg-success/10 text-success';
                statusIcon = 'fa-check-circle';
            } else if (group.state === '警告') {
                statusClass = 'bg-warning/10 text-warning';
                statusIcon = 'fa-exclamation-circle';
            } else {
                statusClass = 'bg-danger/10 text-danger';
                statusIcon = 'fa-times-circle';
            }

            row.innerHTML = `    <td class="px-6 py-4">
                <div class="font-medium">${group.groupId}</div>
                </td>
                <td class="px-6 py-4 text-sm">${group.topicName}</td>
                <td class="px-6 py-4">${group.consumerCount}</td>
                <td class="px-6 py-4">${formatRate(group.consumeRate)}</td>
                <td class="px-6 py-4">${formatNumber(group.totalBacklog)}</td>
                <td class="px-6 py-4">${formatNumber(group.currentOffset)}</td>
                <td class="px-6 py-4">${formatNumber(group.endOffset)}</td>
                <td class="px-6 py-4">${group.maxDelayMs}</td>
                <td class="px-6 py-4">
                    <span class="px-2 py-1 rounded-full text-xs ${statusClass}">
                        <i class="fa ${statusIcon} mr-1"></i>${group.state}        </span>
                </td>`;

            tableBody.appendChild(row);
        });
    };

    // 显示通知
    const showToast = (message, type = 'info') => {
        const toastContainer = document.getElementById('toast-container');

        // 创建通知元素
        const toast = document.createElement('div');

        // 设置样式和内容
        let bgColor, icon;
        switch (type) {
            case 'success':
                bgColor = 'bg-success';
                icon = 'fa-check-circle';
                break;
            case 'error':
                bgColor = 'bg-danger';
                icon = 'fa-times-circle';
                break;
            case 'warning':
                bgColor = 'bg-warning';
                icon = 'fa-exclamation-circle';
                break;
            default:
                bgColor = 'bg-primary';
                icon = 'fa-info-circle';
        }

        toast.className = `${bgColor} text-white px-4 py-3 rounded-lg shadow-lg mb-3 transform transition-all duration-300 translate-x-full opacity-0`;
        toast.innerHTML = `
                <div class="flex items-center">
                    <i class="fa ${icon} mr-2"></i>
                    <span>${message}</span>
                </div>
            `;

        // 添加到容器
        toastContainer.appendChild(toast);

        // 显示通知
        setTimeout(() => {
            toast.classList.remove('translate-x-full', 'opacity-0');
        }, 10);

        // 自动关闭
        setTimeout(() => {
            toast.classList.add('translate-x-full', 'opacity-0');
            setTimeout(() => {
                toast.remove();
            }, 300);
        }, 3000);
    };

    // 显示模态框
    const showModal = (modalId) => {
        const modal = document.getElementById(modalId);
        const modalContent = document.getElementById(`${modalId}-content`);

        // 显示模态框背景
        modal.classList.remove('hidden');

        // 添加动画效果
        setTimeout(() => {
            modalContent.classList.remove('scale-95', 'opacity-0');
            modalContent.classList.add('scale-100', 'opacity-100');
        }, 10);
    };

    // 隐藏模态框
    const hideModal = (modalId) => {
        const modal = document.getElementById(modalId);
        const modalContent = document.getElementById(`${modalId}-content`);

        // 添加动画效果
        modalContent.classList.remove('scale-100', 'opacity-100');
        modalContent.classList.add('scale-95', 'opacity-0');

        // 隐藏模态框背景
        setTimeout(() => {
            modal.classList.add('hidden');
        }, 300);
    };

    // 显示确认删除模态框
    const showConfirmDeleteModal = (topicName) => {
        deletingTopicName = topicName;
        document.getElementById('delete-topic-name').textContent = topicName;
        showModal('confirm-delete-modal');
    };

    // 从API获取集群指标
    const fetchClusterMetrics = async () => {
        try {
            const response = await fetch(`${apiConfig.baseUrl}/kafka/metrics/cluster`);

            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }

            const data = await response.json();

            // 更新UI
            document.getElementById('cluster-name').textContent = data.clusterName;
            document.getElementById('broker-count').textContent = data.brokerCount;
            document.getElementById('topic-count').textContent = data.topicCount;
            document.getElementById('partition-count').textContent = data.partitionCount;
            document.getElementById('message-total').textContent = formatNumber(data.messageTotal24h);

            // 更新状态
            const clusterStatus = document.getElementById('cluster-status');
            if (data.clusterStatus === '健康') {
                clusterStatus.className = 'bg-success text-white text-sm px-3 py-1 rounded-full';
                clusterStatus.innerHTML = '<i class="fa fa-check-circle mr-1"></i>健康';
            } else if (data.clusterStatus === '警告') {
                clusterStatus.className = 'bg-warning text-white text-sm px-3 py-1 rounded-full';
                clusterStatus.innerHTML = '<i class="fa fa-exclamation-circle mr-1"></i>警告';
            } else {
                clusterStatus.className = 'bg-danger text-white text-sm px-3 py-1 rounded-full';
                clusterStatus.innerHTML = '<i class="fa fa-times-circle mr-1"></i>异常';
            }

            // 更新时间
            const updateTime = document.getElementById('update-time');
            if (data.lastUpdateTime) {
                const date = new Date(data.lastUpdateTime);
                updateTime.textContent = date.toLocaleString('zh-CN', {
                    year: 'numeric',
                    month: '2-digit',
                    day: '2-digit',
                    hour: '2-digit',
                    minute: '2-digit',
                    second: '2-digit'
                });
            }

            return data;
        } catch (error) {
            console.error('Failed to fetch cluster metrics:', error);
            showToast('获取集群指标失败: ' + error.message, 'error');
            return null;
        }
    };

    // 从API获取主题指标
    const fetchTopicMetrics = async () => {
        try {
            const response = await fetch(`${apiConfig.baseUrl}/kafka/metrics/topics`);

            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }

            const data = await response.json();
            topicData = data;

            // 渲染表格
            const searchTerm = document.getElementById('topic-search').value;
            renderTopicTable(currentTopicPage, searchTerm);

            return data;
        } catch (error) {
            console.error('Failed to fetch topic metrics:', error);
            showToast('获取主题指标失败: ' + error.message, 'error');
            return null;
        }
    };

    // 从API获取消费者组指标
    const fetchConsumerGroupMetrics = async () => {
        try {
            const response = await fetch(`${apiConfig.baseUrl}/kafka/metrics/consumer-groups`);

            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }

            const data = await response.json();
            consumerGroupData = data;

            // 渲染表格
            const searchTerm = document.getElementById('consumer-group-search').value;
            renderConsumerGroupTable(currentConsumerPage, searchTerm);

            return data;
        } catch (error) {
            console.error('Failed to fetch consumer group metrics:', error);
            showToast('获取消费者组指标失败: ' + error.message, 'error');
            return null;
        }
    };

    // 刷新所有指标
    const refreshAllMetrics = async () => {
        // 显示加载状态
        const refreshBtn = document.getElementById('refresh-btn');
        const refreshStatus = document.getElementById('refresh-status');

        refreshBtn.innerHTML = '<i class="fa fa-spinner fa-spin mr-2"></i><span>刷新中...</span>';
        refreshBtn.disabled = true;
        refreshStatus.textContent = '刷新中...';

        try {
            // 刷新后端数据
            await fetch(`${apiConfig.baseUrl}/kafka/metrics/refresh`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                }
            });

            // 获取最新指标
            await Promise.all([
                fetchClusterMetrics(),
                fetchTopicMetrics(),
                fetchConsumerGroupMetrics()
            ]);

            // 更新图表
            initThroughputChart();

            // 显示成功提示
            showToast('数据已成功刷新', 'success');
        } catch (error) {
            console.error('Failed to refresh metrics:', error);
            showToast('刷新数据失败: ' + error.message, 'error');
        } finally {
            // 恢复按钮状态
            refreshBtn.innerHTML = '<i class="fa fa-refresh mr-2"></i><span>刷新</span>';
            refreshBtn.disabled = false;
            refreshStatus.textContent = '已刷新';
        }
    };

    // 创建主题
    const createTopic = async (topicData) => {
        try {
            const response = await fetch(`${apiConfig.baseUrl}/kafka/admin/topics`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(topicData)
            });

            if (!response.ok) {
                const errorData = await response.json();
                throw new Error(errorData.message || `HTTP error! status: ${response.status}`);
            }

            return true;
        } catch (error) {
            console.error('Failed to create topic:', error);
            showToast('创建主题失败: ' + error.message, 'error');
            return false;
        }
    };

    // 删除主题
    const deleteTopic = async (topicName) => {
        try {
            const response = await fetch(`${apiConfig.baseUrl}/kafka/admin/topics/${topicName}`, {
                method: 'DELETE'
            });

            if (!response.ok) {
                const errorData = await response.json();
                throw new Error(errorData.message || `HTTP error! status: ${response.status}`);
            }

            return true;
        } catch (error) {
            console.error('Failed to delete topic:', error);
            showToast('删除主题失败: ' + error.message, 'error');
            return false;
        }
    };

    // 保存Kafka配置
    const saveKafkaConfig = async (config) => {
        try {
            const response = await fetch(`${apiConfig.baseUrl}/kafka/admin/config`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(config)
            });

            if (!response.ok) {
                const errorData = await response.json();
                throw new Error(errorData.message || `HTTP error! status: ${response.status}`);
            }

            return true;
        } catch (error) {
            console.error('Failed to save Kafka config:', error);
            showToast('保存配置失败: ' + error.message, 'error');
            return false;
        }
    };

    // 初始化事件监听
    const initEventListeners = () => {
        // 刷新按钮
        document.getElementById('refresh-btn').addEventListener('click', refreshAllMetrics);

        // 配置按钮
        document.getElementById('config-btn').addEventListener('click', () => {
            showModal('config-modal');
        });

        // 新建主题按钮
        document.getElementById('create-topic-btn').addEventListener('click', () => {
            showModal('create-topic-modal');
        });

        // 关闭配置模态框
        document.getElementById('close-config-modal').addEventListener('click', () => {
            hideModal('config-modal');
        });

        // 关闭主题模态框
        document.getElementById('close-topic-modal').addEventListener('click', () => {
            hideModal('create-topic-modal');
        });

        // 取消创建主题
        document.getElementById('cancel-create-topic').addEventListener('click', () => {
            hideModal('create-topic-modal');
        });

        // 关闭确认删除模态框
        document.getElementById('close-confirm-modal').addEventListener('click', () => {
            hideModal('confirm-delete-modal');
        });

        // 取消删除
        document.getElementById('cancel-delete').addEventListener('click', () => {
            hideModal('confirm-delete-modal');
        });

        // 确认删除
        document.getElementById('confirm-delete').addEventListener('click', async () => {
            const success = await deleteTopic(deletingTopicName);
            if (success) {
                hideModal('confirm-delete-modal');
                showToast(`主题 "${deletingTopicName}" 已成功删除`, 'success');
                await refreshAllMetrics();
            }
        });

        // 重置配置按钮
        document.getElementById('reset-config-btn').addEventListener('click', () => {
            document.getElementById('bootstrap-servers').value = 'localhost:9092';
            document.getElementById('admin-timeout').value = '5000';
            document.getElementById('metrics-refresh-interval').value = '30000';
            document.getElementById('consumer-group-id').value = 'kafka-monitor-group';
        });

        // 保存配置表单
        document.getElementById('kafka-config-form').addEventListener('submit', async (e) => {
            e.preventDefault();

            const config = {
                bootstrapServers: document.getElementById('bootstrap-servers').value,
                adminTimeout: parseInt(document.getElementById('admin-timeout').value),
                metricsRefreshInterval: parseInt(document.getElementById('metrics-refresh-interval').value),
                consumerGroupId: document.getElementById('consumer-group-id').value
            };

            // 更新API配置
            apiConfig.kafkaConfig = config;
            saveConfigToStorage();

            // 保存到后端
            const success = await saveKafkaConfig(config);
            if (success) {
                hideModal('config-modal');
                showToast('Kafka配置已成功保存', 'success');
                await refreshAllMetrics();
            }
        });

        // 创建主题表单
        document.getElementById('create-topic-form').addEventListener('submit', async (e) => {
            e.preventDefault();

            const topicData = {
                name: document.getElementById('topic-name').value,
                partitions: parseInt(document.getElementById('partition-count-input').value),
                replicas: parseInt(document.getElementById('replica-count').value),
                retentionMs: parseInt(document.getElementById('retention-ms').value)
            };

            const success = await createTopic(topicData);
            if (success) {
                hideModal('create-topic-modal');
                showToast(`主题 "${topicData.name}" 已成功创建`, 'success');
                document.getElementById('create-topic-form').reset();
                await refreshAllMetrics();
            }
        });

        // 主题搜索
        document.getElementById('topic-search').addEventListener('input', (e) => {
            const searchTerm = e.target.value;
            currentTopicPage = 1;
            renderTopicTable(currentTopicPage, searchTerm);
        });

        // 消费者组搜索
        document.getElementById('consumer-group-search').addEventListener('input', (e) => {
            const searchTerm = e.target.value;
            currentConsumerPage = 1;
            renderConsumerGroupTable(currentConsumerPage, searchTerm);
        });


        // 主题分页按钮
        document.getElementById('prev-topic-page').addEventListener('click', () => {
            if (currentTopicPage > 1) {
                currentTopicPage--;
                const searchTerm = document.getElementById('topic-search').value;
                renderTopicTable(currentTopicPage, searchTerm);
            }
        });

        document.getElementById('next-topic-page').addEventListener('click', () => {
            currentTopicPage++;
            const searchTerm = document.getElementById('topic-search').value;
            renderTopicTable(currentTopicPage, searchTerm);
        });

        // 消费者组分页按钮
        document.getElementById('prev-consumer-page').addEventListener('click', () => {
            if (currentConsumerPage > 1) {
                currentConsumerPage--;
                const searchTerm = document.getElementById('consumer-group-search').value;
                renderConsumerGroupTable(currentConsumerPage, searchTerm);
            }
        });

        document.getElementById('next-consumer-page').addEventListener('click', () => {
            currentConsumerPage++;
            const searchTerm = document.getElementById('consumer-group-search').value;
            renderConsumerGroupTable(currentConsumerPage, searchTerm);
        });

        // 图表筛选按钮
        document.querySelectorAll('.chart-filter-btn').forEach(btn => {
            btn.addEventListener('click', () => {
                document.querySelectorAll('.chart-filter-btn').forEach(b => {
                    b.classList.remove('bg-primary', 'text-white');
                    b.classList.add('bg-light', 'text-info');
                });
                btn.classList.remove('bg-light', 'text-info');
                btn.classList.add('bg-primary', 'text-white');

                // 这里可以根据选择的时间范围更新图表数据
                initThroughputChart();
            });
        });
    };

    // 页面加载完成后初始化
    document.addEventListener('DOMContentLoaded', async () => {
        // 加载配置
        loadConfigFromStorage();

        // 初始化事件监听
        initEventListeners();

        // 初始化图表
        initThroughputChart();

        // 初始加载数据
        await Promise.all([
            fetchClusterMetrics(),
            fetchTopicMetrics(),
            fetchConsumerGroupMetrics()
        ]);
    });
</script>
</body>
</html>
